﻿#ifndef _C_RTMP_CLIENT_H
#define _C_RTMP_CLIENT_H

#include <QTcpSocket>

#include "rtmpchunk.h"
#include "amf.h"
#include "crtmpclient.h"

enum clientType
{
    PUBLISHER = 0,
    PLAYER
};

class cRtmpServer;
class cRtmpClient;

struct tagClient
{
    tagClient()
        : cclientType(PUBLISHER),client(NULL) {}
    tagClient(clientType ct,cRtmpClient *c)
        : cclientType(ct),client(c) {}

    clientType cclientType;
    cRtmpClient *client;
};

class cRtmpClient : public QTcpSocket
{
    Q_OBJECT

public:
    enum ConnectionMode
    {
        RTMP_SERVER,
        RTMP_PUBLISHER,
        RTMP_CLIENT
    };

    enum ConnectionState
    {
        HANDSHAKE,
        START_CONNECT,
        START_CREATE_STREAM,
        START_DELETE_STREAM,
        START_PLAY,
        START_PUBLISH,
    };

    explicit cRtmpClient(QObject *parent = nullptr,
                         qintptr socketDescriptor=-1,
                         cRtmpServer *rtmpserver=nullptr);
    ~cRtmpClient();

    /// 发送数据
    qint64 send(QByteArray data);
    qint64 send2(const char *data,qint32 size);
    bool SendMediaData(uint8_t type, uint64_t timestamp, QByteArray payload,int payloadsize);
    bool SendMetaData(AmfObjects meta_data);
    bool SendVideoData(uint64_t timestamp, QByteArray payload, uint32_t payload_size);
    inline bool IsPlaying() { return is_playing_; }
    inline clientType getclientType(void) { return m_clientType; }
    inline QString getstreampath(void) { return stream_path_; }
    inline int getHeartCount(void) { return m_heartCount; }
    inline qintptr getcurSocketId(void) { return m_curSocketId; }
    inline void HeartCount(void) { m_heartCount++; }
    inline void setmaxchunksize(uint32_t size) { max_chunk_size_ = size; }
    inline uint32_t getmaxchunksize(void) { return max_chunk_size_; }
    inline bool isConnected(void) { return this->state() == QAbstractSocket::ConnectedState; }

signals:
    void sockConnected(qintptr conn);
    void sockDisConnect(qintptr conn);
    /// 处理网络二进制消息
    void signalsNetBinary(qintptr conn,QByteArray &data);
    /// 日志消息
    void sockLog(QString log);

public slots:
    /// 处理接收数据
    void OnReadyRead();
    /// 处理连接关闭
    void onDisconnected();
    /// 处理连接成功
    void onConnected();

private:
    bool SendInvokeMessage(uint32_t csid, QByteArray payload);
    void SendRtmpChunks(uint32_t csid, RtmpMessage& rtmp_msg);

private:
    /// 解析信息包
    bool parsePacket(void);
    /// 日志消息
    void showLog(QString log);
    bool HandleConnect();
    bool HandleChunk(QByteArray& buffer);
    bool HandleMessage(RtmpMessage& rtmp_msg);
    bool HandleInvoke(RtmpMessage& rtmp_msg);
    bool HandleNotify(RtmpMessage& rtmp_msg);
    bool HandleVideo(RtmpMessage& rtmp_msg);
    bool HandleAudio(RtmpMessage& rtmp_msg);

    bool HandleCreateStream();
    bool HandleDeleteStream();
    bool HandlePublish();
    void SetPeerBandwidth();
    void SendAcknowledgement();
    void SetChunkSize();
    bool SendNotifyMessage2(uint32_t csid, QByteArray payload,int playloadsize);

    bool HandlePlay();
    bool HandlePlay2();

private:
    cRtmpServer *m_rtmpserver;
    ConnectionMode connection_mode_;
    ConnectionState connection_state_;
    QByteArray m_dataPacket;                    /**< 用于存放接收的数据 */
    RtmpHandshake m_RtmpHandshake;
    RtmpChunk m_RtmpChunk;
    AmfDecoder amf_decoder_;
    AmfEncoder amf_encoder_;
    AmfObjects meta_data_;

    uint32_t max_gop_cache_len_;
    qintptr m_curSocketId;
    QString app_;
    QString stream_name_;
    QString stream_path_;
    uint32_t stream_id_;
    uint32_t max_chunk_size_;
    uint32_t peer_bandwidth_;
    uint32_t acknowledgement_size_;
    QByteArray avc_sequence_header_;
    uint32_t avc_sequence_header_size_;
    QByteArray aac_sequence_header_;
    uint32_t aac_sequence_header_size_;

    bool is_playing_;
    clientType m_clientType;
    int m_heartCount;
};

#endif // CRTMPCLIENT_H
